﻿// SilverlightDesktop.Net - http://www.SilverlightDesktop.net
// Copyright (c) 2008
// by SilverlightDesktop.Net
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Net;
using System.IO;
using System.Reflection;
using SilverlightDesktop.SilverlightDesktopWebService;
using System.ServiceModel;
using System.Windows.Resources;
using System.Windows.Browser;

namespace SilverlightDesktop
{
    public partial class Page : UserControl
    {
        SilverlightDesktopModule objSilverlightDesktopModule;

        private List<UserControl> colUserControl = new List<UserControl>();
        private Panel OriginalParentPanel;
        private Point OriginalStartingDragPoint;

        bool UseWindows = true;
        int intWindowLocationLeft = 80;
        int intWindowLocationTop = 80;
        Point StartingDragPoint;
        string strXAPName;
        string strAssemblyClassName;

        public int intPortalID;
        public int intModuleId;
        public int intUserID;
        public string strPassword;
        public string strWebServiceBase;
        public string strAutoLoadModule;

        public Page(string PortalID, string ModuleId, string UserID, string Password, string WebServiceBase, string AutoLoadModule)
        {
            // Required to initialize variables
            InitializeComponent();
            Loaded += new RoutedEventHandler(Page_Loaded);

            intPortalID = Convert.ToInt32(PortalID);
            intModuleId = Convert.ToInt32(ModuleId);
            intUserID = Convert.ToInt32(UserID);
            strPassword = Password;
            strWebServiceBase = WebServiceBase;
            strAutoLoadModule = AutoLoadModule;
        }

        #region Page_Loaded
        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            // Only show SayHello and Toolbar if AutoLoadModule is not set
            if (strAutoLoadModule == "0")
            {
                SayHelloVisitor();
                ShowProgramIcons();
            }
            else
            {
                // Attempt to AutoLoad the module
                UseWindows = false;
                LoadModuleByUser(Convert.ToInt32(strAutoLoadModule));
            }
        }
        #endregion

        #region SayHelloVisitor
        private void SayHelloVisitor()
        {
            var proxy = new WebServiceSoapClient();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");

            proxy.Endpoint.Address = MyEndpointAddress;
            proxy.HelloUserCompleted += new EventHandler<HelloUserCompletedEventArgs>(proxy_HelloUserCompleted);
            proxy.HelloUserAsync(intPortalID, intModuleId, intUserID, strPassword);
        }

        void proxy_HelloUserCompleted(object sender, HelloUserCompletedEventArgs e)
        {
            HelloVisitor.Text = e.Result.ToString();
        }
        #endregion

        #region ShowProgramIcons
        private void ShowProgramIcons()
        {
            var proxy = new WebServiceSoapClient();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");

            proxy.Endpoint.Address = MyEndpointAddress;
            proxy.GetDesktopModulesCompleted += new EventHandler<GetDesktopModulesCompletedEventArgs>(proxy_GetDesktopModulesCompleted);
            proxy.GetDesktopModulesAsync(intPortalID, intModuleId, intUserID, strPassword);
        }

        void proxy_GetDesktopModulesCompleted(object sender, GetDesktopModulesCompletedEventArgs e)
        {
            SilverlightDesktopModule[] colSilverlightDesktopModule = (SilverlightDesktopModule[])e.Result;

            foreach (SilverlightDesktopModule SilverlightDesktopModule in colSilverlightDesktopModule)
            {
                Button Button = new Button();
                Button.Width = 150;
                Button.Height = 20;
                Button.Content = SilverlightDesktopModule.ModuleName;
                Button.Margin = new Thickness(5.0, 5.0, 5.0, 5.0);
                Button.Tag = SilverlightDesktopModule.ModuleID.ToString();
                Button.Click += new RoutedEventHandler(Button_Click);

                SilverlightIcons.Children.Add(Button);
            }

            // Logout button
            // Only Show Logout button if PortalID = -1 (non-DotNetNuke version)
            if (intPortalID == -1)
            {
                Button objButton = new Button();
                objButton.Width = 150;
                objButton.Height = 20;
                objButton.Content = "Logout";
                objButton.Margin = new Thickness(5.0, 5.0, 5.0, 5.0);
                objButton.Click += new RoutedEventHandler(Logout_Click);

                SilverlightIcons.Children.Add(objButton);
            }
        }

        void Button_Click(object sender, RoutedEventArgs e)
        {
            Button Button = (Button)sender;
            int DesktopModuleID = Convert.ToInt32(Button.Tag);

            // Set Window location
            intWindowLocationLeft = intWindowLocationLeft + 20;
            if (intWindowLocationLeft > 180)
            {
                intWindowLocationLeft = 80;
                intWindowLocationTop = intWindowLocationTop + 20;
            }

            if (intWindowLocationTop > 180)
            {
                intWindowLocationTop = 80;
            }

            LoadModule(DesktopModuleID);
        }
        #endregion

        #region LoadModule
        private void LoadModule(int DesktopModuleID)
        {
            var proxy = new WebServiceSoapClient();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");

            proxy.Endpoint.Address = MyEndpointAddress;
            proxy.GetDesktopModuleCompleted += new EventHandler<GetDesktopModuleCompletedEventArgs>(proxy_GetDesktopModuleCompleted);
            proxy.GetDesktopModuleAsync(DesktopModuleID);
        }

        private void LoadModuleByUser(int DesktopModuleID)
        {
            var proxy = new WebServiceSoapClient();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");

            proxy.Endpoint.Address = MyEndpointAddress;
            proxy.GetDesktopModuleByUserCompleted += new EventHandler<GetDesktopModuleByUserCompletedEventArgs>(proxy_GetDesktopModuleByUserCompleted);
            proxy.GetDesktopModuleByUserAsync(intPortalID, intUserID, DesktopModuleID);
        }
        #endregion

        #region Load Assembly
        void proxy_GetDesktopModuleCompleted(object sender, GetDesktopModuleCompletedEventArgs e)
        {
            objSilverlightDesktopModule = (SilverlightDesktopModule)e.Result;

            strXAPName = objSilverlightDesktopModule.AssemblyName;
            strAssemblyClassName = objSilverlightDesktopModule.ClassName;
            StartDownloader();
        }

        void proxy_GetDesktopModuleByUserCompleted(object sender, GetDesktopModuleByUserCompletedEventArgs e)
        {
            objSilverlightDesktopModule = (SilverlightDesktopModule)e.Result;

            // If the user is not in the proper role to see the module
            // The ModuleID will be set to 0 so show nothing
            if (objSilverlightDesktopModule.ModuleID == 0)
            {
                return;
            }

            // If the ModuleID was not found because it was deleted
            // The ModuleID will be set to -1 
            // The normal default SilverlightDesktop should be shown
            if (objSilverlightDesktopModule.ModuleID == -1)
            {
                SayHelloVisitor();
                ShowProgramIcons();
            }

            strXAPName = objSilverlightDesktopModule.AssemblyName;
            strAssemblyClassName = objSilverlightDesktopModule.ClassName;
            StartDownloader();
        }

        private void StartDownloader()
        {
            WebClient downloader = new WebClient();
            downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
            downloader.OpenReadAsync(new Uri(strXAPName, UriKind.Relative));
        }

        void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            loadAssembly(e.Result);
        }

        private void loadAssembly(Stream s)
        {
            // from http://silverlight.net/forums/p/14941/49437.aspx (BlueAquarius)
            // From http://joel.neubeck.net/2008/03/silverlight-how-to-on-demand-assembly-deployment/

            try
            {
                Uri uri = new Uri(strXAPName.Replace(".xap", ".dll"), UriKind.Relative);
                StreamResourceInfo xapPackageSri = new StreamResourceInfo(s, null);
                StreamResourceInfo assemblySri = Application.GetResourceStream(xapPackageSri, uri);

                AssemblyPart assemblyPart = new AssemblyPart();
                Assembly a = assemblyPart.Load(assemblySri.Stream);

                UserControl objUserControl = (UserControl)a.CreateInstance(strAssemblyClassName);
                if (objUserControl == null)
                {
                    debug("objUserControl is null " + strAssemblyClassName);
                    return;
                }

                // Pass the parameters to the control that it will need to connect to the website
                objUserControl.Tag = string.Format("{0}, {1}, {2}, {3}, {4}", intPortalID, intModuleId, intUserID, strPassword, strWebServiceBase);

                // Add User Control to list of User controls to check as a possible drop point
                // If it implements A Import Interface
                object objObject = objUserControl.GetType().GetInterface("ImportContent", true);
                // If the object is not null then the parent object has a method called "ImportContent"
                if (!(objObject == null))
                {
                    colUserControl.Add(objUserControl);
                }


                if (UseWindows)
                {
                    // Try to call the AddDelegates method on the module being loaded
                    // However, the module may not have the AddDelegates method
                    try
                    {
                        // Create a parmeters array
                        object[] parameters = new object[1];
                        // Add the element that is being dragged to the array
                        parameters.SetValue(this, 0);
                        objUserControl.GetType().InvokeMember("AddDelegates",
                            BindingFlags.InvokeMethod, null, objUserControl, parameters);
                    }
                    catch
                    {
                        // The module does not implement the AddDelegates method
                    }

                    SilverlightWindowControl objSilverlightWindowControl = new SilverlightWindowControl(objSilverlightDesktopModule.WindowSize);
                    objSilverlightWindowControl.Window.Content = objUserControl;
                    objSilverlightWindowControl.WindowName.Text = objSilverlightDesktopModule.ModuleName;
                    Canvas.SetLeft(objSilverlightWindowControl, (double)intWindowLocationLeft);
                    Canvas.SetTop(objSilverlightWindowControl, (double)intWindowLocationTop);

                    this.LayoutRoot.Children.Add(objSilverlightWindowControl);
                }
                else
                {
                    this.LayoutRoot.Children.Add(objUserControl);
                }
            }
            catch (Exception ex)
            {
                debug("Exception when loading the assembly part:");
                debug(ex.ToString());
            }
        }
        #endregion

        #region UpdateElementPosition
        private void UpdateElementPosition(FrameworkElement objFrameworkElement, Point Point)
        {
            Canvas.SetLeft(objFrameworkElement, Point.X - StartingDragPoint.X);
            Canvas.SetTop(objFrameworkElement, Point.Y - StartingDragPoint.Y);
        }
        #endregion

        #region MouseLeftButtonDown
        public void objFrameworkElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //Start Drag
            FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            if (objFrameworkElement.Tag == null)
            {
                return;
            }

            objFrameworkElement.CaptureMouse();

            // Set the starting point for the drag
            StartingDragPoint = e.GetPosition(objFrameworkElement);

            // Remove the element from it's control and move it to the parent
            // if it's Tag contains the words [draggable]
            if (objFrameworkElement.Tag.ToString().Contains("[draggable]"))
            {
                OriginalParentPanel = objFrameworkElement.Parent as Panel;
                OriginalStartingDragPoint = e.GetPosition(OriginalParentPanel);
                OriginalParentPanel.Children.Remove(objFrameworkElement);

                this.LayoutRoot.Children.Add(objFrameworkElement);
                MoveToTop(objFrameworkElement);
                UpdateElementPosition(objFrameworkElement, e.GetPosition(this.LayoutRoot));
            }

            objFrameworkElement.MouseMove += new MouseEventHandler(objFrameworkElement_MouseMove);
            objFrameworkElement.MouseLeftButtonUp += new MouseButtonEventHandler(objFrameworkElement_MouseLeftButtonUp);
        }
        #endregion

        #region MouseMove
        void objFrameworkElement_MouseMove(object sender, MouseEventArgs e)
        {
            FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            Canvas objCanvas = (Canvas)objFrameworkElement.Parent;
            Point Point = e.GetPosition(objCanvas);

            UpdateElementPosition(objFrameworkElement, Point);
        }
        #endregion

        #region MouseLeftButtonUp
        void objFrameworkElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Drag
            FrameworkElement objFrameworkElement = (FrameworkElement)sender;
            objFrameworkElement.ReleaseMouseCapture();

            objFrameworkElement.MouseMove -=
                new MouseEventHandler(objFrameworkElement_MouseMove);
            objFrameworkElement.MouseLeftButtonUp -=
                new MouseButtonEventHandler(objFrameworkElement_MouseLeftButtonUp);

            // If it is an element marked [draggable]
            // try to drop it on a panel stored in the colPanels collection
            if (objFrameworkElement.Tag.ToString().Contains("[draggable]"))
            {
                Point tmpPoint = e.GetPosition(null);
                // Build a list of elements at the current mouse position
                List<UIElement> hits = (List<UIElement>)System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(tmpPoint, this);
                // Loop through all the UserControls in the colUserControl collection
                foreach (UserControl objUserControl in colUserControl)
                {
                    if (hits.Contains(objUserControl))
                    {
                        // Import content
                        // Create a parmeters array
                        object[] parameters = new object[1];
                        // Add the element that is being dragged to the array
                        parameters.SetValue(objFrameworkElement, 0);
                        // invoke the "ImportContent" on the parent object passing the parameters array that 
                        // contains the element being dragged
                        bool boolImport = (bool)objUserControl.GetType().InvokeMember("ImportContent",
                            BindingFlags.InvokeMethod, null, objUserControl, parameters);
                        break;
                    }
                }

                // Remove the element from the main canvas
                this.LayoutRoot.Children.Remove(objFrameworkElement);

                // Move the element back to it's original position
                OriginalParentPanel.Children.Add(objFrameworkElement);
                Canvas.SetLeft(objFrameworkElement, OriginalStartingDragPoint.X - StartingDragPoint.X);
                Canvas.SetTop(objFrameworkElement, OriginalStartingDragPoint.Y - StartingDragPoint.Y);
                OriginalParentPanel.UpdateLayout();
            }
        }
        #endregion

        #region MoveToTop
        private void MoveToTop(FrameworkElement objFrameworkElement)
        {
            Panel objPanel = (Panel)objFrameworkElement.Parent;

            //Find the highest elemnt
            int intHighestElement = 0;
            foreach (UIElement UIElement in objPanel.Children)
            {
                int intTmpHighestElement = Canvas.GetZIndex(UIElement);
                intHighestElement = (intTmpHighestElement > intHighestElement) ? intTmpHighestElement : intHighestElement;
            }

            Canvas.SetZIndex(objFrameworkElement, intHighestElement + 1);
        }
        #endregion

        #region Debug
        private void debug(string p)
        {
            DebugBox.Text = p;
        }
        #endregion

        #region Logout
        void Logout_Click(object sender, RoutedEventArgs e)
        {
            var proxy = new WebServiceSoapClient();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase + "Webservice.asmx");

            proxy.Endpoint.Address = MyEndpointAddress;
            proxy.LogoutAsync(intPortalID, intModuleId, intUserID, strPassword);

            Uri Uri = new Uri(strWebServiceBase.ToLower().Replace(@"webservice/", ""));
            HtmlPage.Window.Navigate(Uri);
        }
        #endregion
    }
}
